/**
 * Copyright 2013-2022 the original author or authors from the Jeddict project (https://jeddict.github.io/).
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package io.github.jeddict.jpa.modeler.properties.entitygraph;

import javax.swing.JOptionPane;
import static javax.swing.SwingUtilities.invokeLater;
import io.github.jeddict.jpa.modeler.widget.EntityWidget;
import io.github.jeddict.jpa.modeler.navigator.nodes.CheckableAttributeNode;
import io.github.jeddict.jpa.modeler.navigator.nodes.TreeNode;
import io.github.jeddict.jpa.modeler.properties.entitygraph.nodes.EGInternalNode;
import io.github.jeddict.jpa.modeler.properties.entitygraph.nodes.EGLeafNode;
import io.github.jeddict.jpa.modeler.properties.entitygraph.nodes.EGRootNode;
import io.github.jeddict.jpa.spec.NamedAttributeNode;
import io.github.jeddict.jpa.spec.NamedEntityGraph;
import io.github.jeddict.jpa.spec.NamedSubgraph;
import io.github.jeddict.jpa.spec.extend.Attribute;
import org.netbeans.modeler.properties.EntityComponent;
import org.netbeans.modeler.properties.spec.Entity;
import org.netbeans.modeler.properties.spec.RowValue;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.view.OutlineView;

public class NamedEntityGraphPanel extends EntityComponent<NamedEntityGraph> implements ExplorerManager.Provider {

    private final ExplorerManager manager;

    private NamedEntityGraph namedEntityGraph;
    private final EntityWidget entityWidget;
    private EGRootNode node;

    public NamedEntityGraphPanel(EntityWidget entityWidget) {
        this.entityWidget = entityWidget;
        manager = new ExplorerManager();
    }

    @Override
    public void postConstruct() {
        initComponents();
    }

    @Override
    public void init() {
        invokeLater(() -> {
            node = new EGRootNode(entityWidget, namedEntityGraph, new NamedEGChildFactory(), new CheckableAttributeNode(namedEntityGraph != null));
            manager.setRootContext(node);
            node.init();
        });
    }

    @Override
    public void createEntity(Class<? extends Entity> entityWrapperType) {
        this.setTitle("Create new Named Entity Graph");
        if (entityWrapperType == RowValue.class) {
            this.setEntity(new RowValue(new Object[3]));
        }
        namedEntityGraph = null;
        name_TextField.setText("");
    }

    @Override
    public void updateEntity(Entity<NamedEntityGraph> entityValue) {
        this.setTitle("Update Named Entity Graph");
        if (entityValue.getClass() == RowValue.class) {
            this.setEntity(entityValue);
            Object[] row = ((RowValue) entityValue).getRow();
            namedEntityGraph = (NamedEntityGraph) row[0];
            name_TextField.setText(namedEntityGraph.getName());
        }
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        rootLayeredPane = new javax.swing.JLayeredPane();
        graphLayeredPane = new javax.swing.JLayeredPane();
        outlineView = new OutlineView("Entity Graph");
        finalGraph_LayeredPane = new javax.swing.JLayeredPane();
        finalGraph_Label = new javax.swing.JLabel();
        finalGraph_Button = new javax.swing.JButton();
        actionLayeredPane = new javax.swing.JLayeredPane();
        save_Button = new javax.swing.JButton();
        cancel_Button = new javax.swing.JButton();
        nameLayeredPane = new javax.swing.JLayeredPane();
        name_Label = new javax.swing.JLabel();
        name_TextField = new javax.swing.JTextField();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);

        graphLayeredPane.setLayout(new java.awt.GridLayout(1, 0));

        //outlineView.setDefaultActionAllowed(false);
        //outlineView.setDoubleBuffered(true);
        //outlineView.setDragSource(false);
        //outlineView.setDropTarget(false)
        graphLayeredPane.add(outlineView);

        finalGraph_Label.setFont(new java.awt.Font("Arial", 1, 11)); // NOI18N
        finalGraph_Label.setForeground(new java.awt.Color(82, 82, 82));
        org.openide.awt.Mnemonics.setLocalizedText(finalGraph_Label, org.openide.util.NbBundle.getMessage(NamedEntityGraphPanel.class, "NamedEntityGraphPanel.finalGraph_Label.text")); // NOI18N

        finalGraph_Button.setFont(new java.awt.Font("Tahoma", 1, 10)); // NOI18N
        finalGraph_Button.setForeground(new java.awt.Color(50, 50, 50));
        org.openide.awt.Mnemonics.setLocalizedText(finalGraph_Button, org.openide.util.NbBundle.getMessage(NamedEntityGraphPanel.class, "NamedEntityGraphPanel.finalGraph_Button.text")); // NOI18N
        finalGraph_Button.setMargin(new java.awt.Insets(1, 5, 1, 5));
        finalGraph_Button.setPreferredSize(new java.awt.Dimension(50, 25));
        finalGraph_Button.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                finalGraph_ButtonActionPerformed(evt);
            }
        });

        finalGraph_LayeredPane.setLayer(finalGraph_Label, javax.swing.JLayeredPane.DEFAULT_LAYER);
        finalGraph_LayeredPane.setLayer(finalGraph_Button, javax.swing.JLayeredPane.DEFAULT_LAYER);

        javax.swing.GroupLayout finalGraph_LayeredPaneLayout = new javax.swing.GroupLayout(finalGraph_LayeredPane);
        finalGraph_LayeredPane.setLayout(finalGraph_LayeredPaneLayout);
        finalGraph_LayeredPaneLayout.setHorizontalGroup(
            finalGraph_LayeredPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(finalGraph_LayeredPaneLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(finalGraph_Label)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(finalGraph_Button, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(20, Short.MAX_VALUE))
        );
        finalGraph_LayeredPaneLayout.setVerticalGroup(
            finalGraph_LayeredPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(finalGraph_LayeredPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(finalGraph_Label)
                .addComponent(finalGraph_Button, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );

        actionLayeredPane.setLayout(new java.awt.FlowLayout());

        org.openide.awt.Mnemonics.setLocalizedText(save_Button, org.openide.util.NbBundle.getMessage(NamedEntityGraphPanel.class, "NamedEntityGraphPanel.save_Button.text")); // NOI18N
        save_Button.setToolTipText(org.openide.util.NbBundle.getMessage(NamedEntityGraphPanel.class, "NamedEntityGraphPanel.save_Button.toolTipText")); // NOI18N
        save_Button.setPreferredSize(new java.awt.Dimension(60, 30));
        save_Button.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                save_ButtonActionPerformed(evt);
            }
        });
        actionLayeredPane.add(save_Button);

        org.openide.awt.Mnemonics.setLocalizedText(cancel_Button, org.openide.util.NbBundle.getMessage(NamedEntityGraphPanel.class, "NamedEntityGraphPanel.cancel_Button.text")); // NOI18N
        cancel_Button.setToolTipText(org.openide.util.NbBundle.getMessage(NamedEntityGraphPanel.class, "NamedEntityGraphPanel.cancel_Button.toolTipText")); // NOI18N
        cancel_Button.setPreferredSize(new java.awt.Dimension(70, 30));
        cancel_Button.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancel_ButtonActionPerformed(evt);
            }
        });
        actionLayeredPane.add(cancel_Button);

        nameLayeredPane.setLayout(new java.awt.BorderLayout());

        org.openide.awt.Mnemonics.setLocalizedText(name_Label, org.openide.util.NbBundle.getMessage(NamedEntityGraphPanel.class, "NamedEntityGraphPanel.name_Label.text")); // NOI18N
        nameLayeredPane.add(name_Label, java.awt.BorderLayout.WEST);

        name_TextField.setText(org.openide.util.NbBundle.getMessage(NamedEntityGraphPanel.class, "NamedEntityGraphPanel.name_TextField.text")); // NOI18N
        name_TextField.setPreferredSize(new java.awt.Dimension(10, 15));
        nameLayeredPane.add(name_TextField, java.awt.BorderLayout.CENTER);

        rootLayeredPane.setLayer(graphLayeredPane, javax.swing.JLayeredPane.DEFAULT_LAYER);
        rootLayeredPane.setLayer(finalGraph_LayeredPane, javax.swing.JLayeredPane.DEFAULT_LAYER);
        rootLayeredPane.setLayer(actionLayeredPane, javax.swing.JLayeredPane.DEFAULT_LAYER);
        rootLayeredPane.setLayer(nameLayeredPane, javax.swing.JLayeredPane.DEFAULT_LAYER);

        javax.swing.GroupLayout rootLayeredPaneLayout = new javax.swing.GroupLayout(rootLayeredPane);
        rootLayeredPane.setLayout(rootLayeredPaneLayout);
        rootLayeredPaneLayout.setHorizontalGroup(
            rootLayeredPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(graphLayeredPane)
            .addGroup(rootLayeredPaneLayout.createSequentialGroup()
                .addComponent(nameLayeredPane)
                .addContainerGap())
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, rootLayeredPaneLayout.createSequentialGroup()
                .addComponent(finalGraph_LayeredPane)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(actionLayeredPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );
        rootLayeredPaneLayout.setVerticalGroup(
            rootLayeredPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(rootLayeredPaneLayout.createSequentialGroup()
                .addComponent(graphLayeredPane, javax.swing.GroupLayout.PREFERRED_SIZE, 415, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(nameLayeredPane, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(rootLayeredPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(actionLayeredPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, rootLayeredPaneLayout.createSequentialGroup()
                        .addComponent(finalGraph_LayeredPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addContainerGap())))
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(rootLayeredPane)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(rootLayeredPane)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private boolean validateField() {
        if (this.name_TextField.getText().trim().length() <= 0 /*|| Pattern.compile("[^\\w-]").matcher(this.id_TextField.getText().trim()).find()*/) {
            JOptionPane.showMessageDialog(this, "Name field can't be empty", "Invalid Value", javax.swing.JOptionPane.WARNING_MESSAGE);
            return false;
        }//I18n
//        if (this.query_TextArea.getText().trim().length() <= 0 /*|| Pattern.compile("[^\\w-]").matcher(this.id_TextField.getText().trim()).find()*/) {
//            JOptionPane.showMessageDialog(this, "Query field can't be empty", "Invalid Value", javax.swing.JOptionPane.WARNING_MESSAGE);
//            return false;
//        }//I18n
        return true;
    }

    void loadEntityGraph(NamedEntityGraph namedEntityGraph) {
        for (TreeNode childNode : node.getChildList()) {
            loadSubGraph(namedEntityGraph, childNode);
        }
    }

    void loadSubGraph(NamedEntityGraph namedEntityGraph, TreeNode childNode) {
        if (childNode.getCheckableNode() == null || !childNode.getCheckableNode().isSelected()) {
            return;
        }

        if (childNode instanceof EGInternalNode) {
            String name = ((Attribute) (((EGInternalNode) childNode).getParentAttributeWidget().getBaseElementSpec())).getName();
            NamedAttributeNode attributeNode = new NamedAttributeNode(name);
            namedEntityGraph.addNamedAttributeNode(attributeNode);
            NamedSubgraph subGraph = new NamedSubgraph(name + ".Graph");
            for (TreeNode subChildNode : ((EGInternalNode) childNode).getChildList()) {
                loadSubGraph(namedEntityGraph, subGraph, subChildNode);
            }
            if (!subGraph.getNamedAttributeNode().isEmpty()) {
                namedEntityGraph.addSubgraph(subGraph);
                attributeNode.setSubgraph(subGraph.getName());
            }

        } else if (childNode instanceof EGLeafNode) {
            String name = ((Attribute) (((EGLeafNode) childNode).getLeafAttributeWidget().getBaseElementSpec())).getName();
            if (childNode.getCheckableNode().isCheckEnabled()) {
                namedEntityGraph.addNamedAttributeNode(new NamedAttributeNode(name));
            }
        }
    }

    void loadSubGraph(NamedEntityGraph namedEntityGraph, NamedSubgraph subGraph, TreeNode childNode) {
        if (childNode.getCheckableNode() == null || !childNode.getCheckableNode().isSelected()) {
            return;
        }
        if (childNode instanceof EGInternalNode) {
            String name = ((Attribute) (((EGInternalNode) childNode).getParentAttributeWidget().getBaseElementSpec())).getName();
            NamedAttributeNode attributeNode = new NamedAttributeNode(name);
            subGraph.addNamedAttributeNode(attributeNode);
            NamedSubgraph childSubGraph = new NamedSubgraph(name + ".Graph");
            for (TreeNode subChildNode : ((EGInternalNode) childNode).getChildList()) {
                loadSubGraph(namedEntityGraph, childSubGraph, subChildNode);
            }
            if (!childSubGraph.getNamedAttributeNode().isEmpty()) {
                namedEntityGraph.addSubgraph(childSubGraph);
                attributeNode.setSubgraph(childSubGraph.getName());
            }
        } else if (childNode instanceof EGLeafNode) {
            String name = ((Attribute) (((EGLeafNode) childNode).getLeafAttributeWidget().getBaseElementSpec())).getName();
            if (childNode.getCheckableNode().isCheckEnabled()) {
                subGraph.addNamedAttributeNode(new NamedAttributeNode(name));
            }
        }
    }

    private void save_ButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_save_ButtonActionPerformed
        if (!validateField()) {
            return;
        }
        if (this.getEntity().getClass() == RowValue.class) {
            Object[] row = ((RowValue) this.getEntity()).getRow();
            if (row[0] == null) {
                namedEntityGraph = new NamedEntityGraph();
            } else {
                namedEntityGraph = (NamedEntityGraph) row[0];
                namedEntityGraph.getNamedAttributeNode().clear();
                namedEntityGraph.getSubclassSubgraph().clear();
                namedEntityGraph.getSubgraph().clear();
            }
        }

        namedEntityGraph.setName(name_TextField.getText());
        loadEntityGraph(namedEntityGraph);

        if (this.getEntity().getClass() == RowValue.class) {
            Object[] row = ((RowValue) this.getEntity()).getRow();
            row[0] = namedEntityGraph;
            row[1] = namedEntityGraph.isEnable();
            row[2] = namedEntityGraph.getName();
        }
        saveActionPerformed(evt);
    }//GEN-LAST:event_save_ButtonActionPerformed

    private void cancel_ButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancel_ButtonActionPerformed
        cancelActionPerformed(evt);
    }//GEN-LAST:event_cancel_ButtonActionPerformed

    private void finalGraph_ButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_finalGraph_ButtonActionPerformed
        NamedEntityGraph namedEntityGraph = new NamedEntityGraph();
        loadEntityGraph(namedEntityGraph);
        ExecutionGraphPanel dialog = new ExecutionGraphPanel(entityWidget, namedEntityGraph);
        dialog.setVisible(true);
    }//GEN-LAST:event_finalGraph_ButtonActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLayeredPane actionLayeredPane;
    private javax.swing.JButton cancel_Button;
    private javax.swing.JButton finalGraph_Button;
    private javax.swing.JLabel finalGraph_Label;
    private javax.swing.JLayeredPane finalGraph_LayeredPane;
    private javax.swing.JLayeredPane graphLayeredPane;
    private javax.swing.JLayeredPane nameLayeredPane;
    private javax.swing.JLabel name_Label;
    private javax.swing.JTextField name_TextField;
    private javax.swing.JScrollPane outlineView;
    private javax.swing.JLayeredPane rootLayeredPane;
    private javax.swing.JButton save_Button;
    // End of variables declaration//GEN-END:variables

    @Override
    public ExplorerManager getExplorerManager() {
        return manager;
    }

}
